import * as fs from 'fs';
import * as path from 'path';
import * as xml2js from 'xml2js';
import { logger } from '../utils/logger';
import { LanguageConfig, ExtractionTask } from '../types';
import axios from 'axios';

/**
 * 语言包数据结构
 * 外层Map: 语言代码 -> 翻译映射
 * 内层Map: 翻译键 -> 翻译值
 */
export type TranslationPack = Map<string, Map<string, string>>;

/**
 * 语言包加载服务
 * 负责从不同来源加载语言包数据
 */
export class TranslationPackLoader {
  private translationPack: TranslationPack = new Map();
  private xmlParser: xml2js.Parser;

  constructor() {
    this.xmlParser = new xml2js.Parser({ explicitArray: false });
  }

  /**
   * 获取指定语言的翻译值
   * @param language 语言代码
   * @param key 翻译键
   * @returns 翻译值，如果不存在则返回undefined
   */
  public getTranslation(language: string, key: string): string | undefined {
    const langMap = this.translationPack.get(language);
    if (!langMap) return undefined;
    return langMap.get(key);
  }

  /**
   * 检查指定语言是否有某个翻译键的值
   * @param language 语言代码
   * @param key 翻译键
   * @returns 是否有翻译
   */
  public hasTranslation(language: string, key: string): boolean {
    const langMap = this.translationPack.get(language);
    if (!langMap) return false;
    return langMap.has(key);
  }

  /**
   * 获取所有支持的语言列表
   * @returns 语言代码数组
   */
  public getSupportedLanguages(): string[] {
    return Array.from(this.translationPack.keys());
  }

  /**
   * 加载多个语言配置
   * @param configs 语言配置数组
   */
  public async loadLanguageConfigs(configs: LanguageConfig[]): Promise<boolean> {
    try {
      logger.info('开始加载语言配置', { configCount: configs.length });

      if (configs.length === 0) {
        logger.warn('未找到任何语言配置');
        return false;
      }

      for (const config of configs) {
        await this.processLanguageSource(config);
      }

      logger.info('语言包加载完成', {
        totalLanguages: this.translationPack.size,
        keys: [...this.translationPack.entries()].map(([lang, map]) => ({
          language: lang,
          keyCount: map.size,
        })),
      });

      return this.translationPack.size > 0;
    } catch (error) {
      logger.error('语言包加载出错', {
        error: error instanceof Error ? error.message : String(error),
      });
      return false;
    }
  }

  /**
   * 处理单个语言配置源
   * @param config 语言配置
   */
  private async processLanguageSource(config: LanguageConfig): Promise<void> {
    try {
      const { sourcePath, language, format, excludePatterns } = config;
      const encoding = (config.encoding as BufferEncoding) || 'utf-8';

      // 检查排除模式
      if (this.shouldExclude(sourcePath, excludePatterns)) {
        logger.debug('文件被排除模式过滤', { path: sourcePath, patterns: excludePatterns });
        return;
      }

      // 检查路径是否存在
      if (!fs.existsSync(sourcePath)) {
        logger.warn('语言资源路径不存在', { path: sourcePath, language });
        return;
      }

      // 判断是文件还是目录
      const stats = fs.statSync(sourcePath);
      if (stats.isFile()) {
        await this.parseLanguageFile(sourcePath, language, format, encoding);
      } else if (stats.isDirectory()) {
        await this.processLanguageDirectory(
          sourcePath,
          language,
          format,
          encoding,
          excludePatterns
        );
      }
    } catch (error) {
      logger.error('处理语言配置源出错', {
        config,
        error: error instanceof Error ? error.message : String(error),
      });
    }
  }

  /**
   * 处理语言目录
   * @param dirPath 目录路径
   * @param language 语言代码
   * @param format 文件格式
   * @param encoding 文件编码
   * @param excludePatterns 排除模式
   */
  private async processLanguageDirectory(
    dirPath: string,
    language: string,
    format?: string,
    encoding: BufferEncoding = 'utf-8',
    excludePatterns?: string[]
  ): Promise<void> {
    try {
      const entries = fs.readdirSync(dirPath, { withFileTypes: true });

      for (const entry of entries) {
        const fullPath = path.join(dirPath, entry.name);

        // 检查排除模式
        if (this.shouldExclude(fullPath, excludePatterns)) {
          continue;
        }

        if (entry.isFile()) {
          await this.parseLanguageFile(fullPath, language, format, encoding);
        } else if (entry.isDirectory()) {
          await this.processLanguageDirectory(
            fullPath,
            language,
            format,
            encoding,
            excludePatterns
          );
        }
      }
    } catch (error) {
      logger.error('处理语言目录出错', {
        dir: dirPath,
        language,
        error: error instanceof Error ? error.message : String(error),
      });
    }
  }

  /**
   * 解析语言文件
   * @param filePath 文件路径
   * @param language 语言代码
   * @param format 文件格式，如果未指定则自动推断
   * @param encoding 文件编码
   */
  private async parseLanguageFile(
    filePath: string,
    language: string,
    format?: string,
    encoding: BufferEncoding = 'utf-8'
  ): Promise<void> {
    try {
      // 如果未指定格式，基于文件扩展名自动推断
      const actualFormat = format || this.inferFormatFromFile(filePath);
      if (!actualFormat) {
        logger.debug('无法确定文件格式，跳过处理', { filePath });
        return;
      }

      // 确保语言映射存在
      if (!this.translationPack.has(language)) {
        this.translationPack.set(language, new Map<string, string>());
      }

      // 根据文件格式选择解析方法
      switch (actualFormat.toLowerCase()) {
        case 'xml':
          await this.parseXmlFile(filePath, language, encoding);
          break;
        case 'properties':
        case 'strings':
          await this.parsePropertiesFile(filePath, language, encoding);
          break;
        case 'json':
          await this.parseJsonFile(filePath, language, encoding);
          break;
        default:
          logger.debug('不支持的文件格式', { filePath, format: actualFormat });
      }
    } catch (error) {
      logger.error('解析语言文件出错', {
        file: filePath,
        language,
        error: error instanceof Error ? error.message : String(error),
      });
    }
  }

  /**
   * 根据文件推断格式
   * @param filePath 文件路径
   * @returns 推断的格式
   */
  private inferFormatFromFile(filePath: string): string | null {
    const ext = path.extname(filePath).toLowerCase();
    const fileName = path.basename(filePath).toLowerCase();

    if (ext === '.xml' && fileName.includes('strings')) {
      return 'xml';
    } else if (ext === '.strings') {
      return 'strings';
    } else if (ext === '.properties') {
      return 'properties';
    } else if (ext === '.json') {
      return 'json';
    }

    return null;
  }

  /**
   * 判断路径是否应该被排除
   * @param filePath 文件路径
   * @param excludePatterns 排除模式数组
   * @returns 是否应被排除
   */
  private shouldExclude(filePath: string, excludePatterns?: string[]): boolean {
    if (!excludePatterns || excludePatterns.length === 0) {
      return false;
    }

    // 简单的通配符匹配
    return excludePatterns.some(pattern => {
      // 将通配符转为正则表达式
      const regexPattern = pattern.replace(/\./g, '\\.').replace(/\*/g, '.*').replace(/\?/g, '.');

      const regex = new RegExp(`^${regexPattern}$`);
      return regex.test(filePath);
    });
  }

  /**
   * 解析XML文件（Android strings.xml）
   * @param filePath 文件路径
   * @param language 语言代码
   * @param encoding 文件编码
   */
  private async parseXmlFile(
    filePath: string,
    language: string,
    encoding: BufferEncoding = 'utf-8'
  ): Promise<void> {
    try {
      const content = fs.readFileSync(filePath, { encoding });
      const result = await this.xmlParser.parseStringPromise(content);

      if (result.resources && result.resources.string) {
        const langMap = this.translationPack.get(language)!;

        // 处理单个string
        if (!Array.isArray(result.resources.string)) {
          if (result.resources.string.$ && result.resources.string.$.name) {
            langMap.set(
              result.resources.string.$.name,
              result.resources.string._ || result.resources.string.$.name
            );
          }
        } else {
          // 处理多个string
          for (const item of result.resources.string) {
            if (item.$ && item.$.name) {
              langMap.set(item.$.name, item._ || item.$.name);
            }
          }
        }

        logger.info('解析XML语言文件成功', {
          file: filePath,
          language,
          keyCount: langMap.size,
        });
      }
    } catch (error) {
      logger.error('解析XML语言文件出错', {
        file: filePath,
        language,
        error: error instanceof Error ? error.message : String(error),
      });
    }
  }

  /**
   * 解析属性文件（.properties或.strings）
   * @param filePath 文件路径
   * @param language 语言代码
   * @param encoding 文件编码
   */
  private async parsePropertiesFile(
    filePath: string,
    language: string,
    encoding: BufferEncoding = 'utf-8'
  ): Promise<void> {
    try {
      const content = fs.readFileSync(filePath, { encoding });
      const lines = content.split('\n');

      const langMap = this.translationPack.get(language)!;

      for (const line of lines) {
        // 跳过注释和空行
        if (line.trim().startsWith('#') || line.trim() === '') {
          continue;
        }

        // iOS .strings 格式: "key" = "value";
        const iosMatch = line.match(/^"([^"]+)"\s*=\s*"([^"]+)";$/);
        if (iosMatch) {
          langMap.set(iosMatch[1], iosMatch[2]);
          continue;
        }

        // Java .properties 格式: key=value
        const javaMatch = line.match(/^([^=]+)=(.*)$/);
        if (javaMatch) {
          langMap.set(javaMatch[1].trim(), javaMatch[2].trim());
        }
      }

      logger.info('解析属性文件成功', {
        file: filePath,
        language,
        keyCount: langMap.size,
      });
    } catch (error) {
      logger.error('解析属性文件出错', {
        file: filePath,
        language,
        error: error instanceof Error ? error.message : String(error),
      });
    }
  }

  /**
   * 解析JSON文件
   * @param filePath 文件路径
   * @param language 语言代码
   * @param encoding 文件编码
   */
  private async parseJsonFile(
    filePath: string,
    language: string,
    encoding: BufferEncoding = 'utf-8'
  ): Promise<void> {
    try {
      const content = fs.readFileSync(filePath, { encoding });
      const json = JSON.parse(content);

      const langMap = this.translationPack.get(language)!;

      // 将JSON对象扁平化
      const flattenObject = (obj: any, prefix = ''): void => {
        for (const [key, value] of Object.entries(obj)) {
          const newKey = prefix ? `${prefix}.${key}` : key;

          if (typeof value === 'string') {
            langMap.set(newKey, value);
          } else if (typeof value === 'object' && value !== null) {
            flattenObject(value, newKey);
          }
        }
      };

      flattenObject(json);

      logger.info('解析JSON语言文件成功', {
        file: filePath,
        language,
        keyCount: langMap.size,
      });
    } catch (error) {
      logger.error('解析JSON语言文件出错', {
        file: filePath,
        language,
        error: error instanceof Error ? error.message : String(error),
      });
    }
  }

  // 按需下载语言包
  public async languagePackUrlList(
    apiUrl: string,
    languages: string[]
  ): Promise<Map<string, string> | boolean> {
    try {
      logger.info('语言包请求参数:', { apiUrl, languages });

      // 尝试请求API获取语言包
      const response = await axios.get(apiUrl, {
        params: {},
        timeout: 15000, // 15秒超时
      });

      if (response.status === 200 && response.data) {
        const langMap = new Map<string, string>();
        // 处理API返回的语言包数据
        for (const language of languages) {
          if (response.data[language]) {
            for (const [key, value] of Object.entries(response.data[language])) {
              langMap.set(key, value as string);
            }
          }
        }
        logger.info('按需下载语言包成功', { langMap });
        return langMap;
      } else {
        logger.warn('按需下载语言包失败', { statusCode: response.status });
        return false;
      }
    } catch (error) {
      logger.error('按需下载语言包出错', {
        error: error instanceof Error ? error.message : String(error),
      });
      return false;
    }
  }

  public async getLanguagePackData(languageUrl: string): Promise<Object> {
    const response = await axios.get(languageUrl, {
      params: {},
      timeout: 15000, // 15秒超时
    });
    return response.data;
  }

  /**
   * 从API加载语言包
   * @param apiUrl API地址
   * @param languages 需要加载的语言列表
   */
  public async loadFromApi(apiUrl: string, languages: string[]): Promise<boolean> {
    logger.info('开始从API加载可用的语言包列表', { apiUrl, languages });
    const languageUrls = await this.languagePackUrlList(apiUrl, languages);
    logger.info('API返回的可用的语言包列表:', { languageUrls });

    // 如果获取到了语言包URL列表，则并行下载所有语言包
    if (languageUrls && Object.keys(languageUrls).length > 0) {
      try {
        logger.info('开始并行下载所有语言包');

        // 创建下载任务数组
        const downloadTasks = Object.entries(languageUrls).map(async ([language, url]) => {
          try {
            logger.debug(`开始下载语言包: ${language}`, { url });
            const languageData = await this.getLanguagePackData(url as string);

            // 将语言包数据转换为Map
            const langMap = new Map<string, string>();
            for (const [key, value] of Object.entries(languageData)) {
              langMap.set(key, value as string);
            }

            // 直接保存到翻译包中
            this.translationPack.set(language, langMap);

            logger.debug(`语言包 ${language} 下载并保存成功`, {
              keyCount: langMap.size,
            });

            return { language, success: true, keyCount: langMap.size };
          } catch (error) {
            logger.error(`下载语言包失败: ${language}`, {
              error: error instanceof Error ? error.message : String(error),
              url,
            });
            return { language, success: false, error };
          }
        });

        // 并行执行所有下载任务
        const results = await Promise.all(downloadTasks);

        // 统计下载结果
        const successCount = results.filter(result => result.success).length;

        logger.info('语言包并行下载完成', {
          total: results.length,
          success: successCount,
          failed: results.length - successCount,
          languages: this.translationPack.size,
          totalKeys: [...this.translationPack.values()].reduce((sum, map) => sum + map.size, 0),
        });

        return successCount > 0;
      } catch (error) {
        logger.error('并行下载语言包过程中发生错误', {
          error: error instanceof Error ? error.message : String(error),
        });
        return false;
      }
    }
    return false;
  }

  /**
   * 从本地文件加载语言包
   * @param task 提取任务配置
   */
  public async loadFromLocalFiles(task: ExtractionTask): Promise<boolean> {
    try {
      logger.info('开始从本地文件加载语言包');

      // 收集所有平台的语言配置
      const configs: LanguageConfig[] = [];

      // 收集 Android 资源目录
      if (task.translationConfig?.android?.resourcePaths) {
        configs.push(...task.translationConfig.android.resourcePaths);
      }

      // 收集 iOS 资源目录
      if (task.translationConfig?.ios?.resourcePaths) {
        configs.push(...task.translationConfig.ios.resourcePaths);
      }

      // 收集 Web 资源目录
      if (task.translationConfig?.web?.resourcePaths) {
        configs.push(...task.translationConfig.web.resourcePaths);
      }

      // 加载所有配置
      return await this.loadLanguageConfigs(configs);
    } catch (error) {
      logger.error('本地语言包加载出错', {
        error: error instanceof Error ? error.message : String(error),
      });
      return false;
    }
  }
}
